home *** CD-ROM | disk | FTP | other *** search
- include paint.pub
- ;PAINT.COM for the IBM Personal Computer - 1987 by Jeff Prosise
-
- bios_data segment at 40h
- org 1Ah
- buffer_head dw ? ;pointer to keyboard buffer head
- buffer_tail dw ? ;pointer to keyboard buffer tail
- org 63h
- addr_6845 dw ? ;CRT Controller address
- org 80h
- buffer_start dw ? ;starting keyboard buffer address
- buffer_end dw ? ;ending keyboard buffer address
- bios_data ends
-
- code segment para public 'code'
- assume cs:code
- org 100h
- begin: jmp main
-
- copyright db 'PAINT 1.0 (c) 1987 Ziff Communications Co.',13,10
- db 'PC Magazine ',254,' Jeff Prosise',13,10,'$',1Ah
-
- errmsg1 db 13,10,'File not found',13,10,'$'
- errmsg2 db 13,10,'Error reading file',13,10,'$'
- errmsg3 db 13,10,'Not enough memory',13,10,'$'
-
- kbcode db 10h ;get keystroke function code
- fileptr dw 81h ;pointer to file name text
- data_segment dw ? ;buffer segment
- doscolor db ? ;screen color before execution
- insert_flag db 0 ;0=overwrite, 1=insert
- write_mode db 0 ;video insertion mode
- bufferptr db 0 ;pointer to current buffer page
- maxpage db 0 ;maximum page number
- mode db 0 ;0=color, 1=monochrome
- columns db ? ;number of display columns -1
- lcolumns dw ? ;number of display columns
- crtc_addr dw ? ;CRT Controller base address
- blockxy dw 0FFFFh ;first corner of block
- attribute db 1Fh ;current paint attribute
- graphics db 0 ;current box character
- defchar db ? ;default box character
- boxid db ? ;box environment byte
- maskval db 01010101b ;graphics mask value
- menu_attr db 1Bh ;menu line attribute
- video_segment dw 0B800h ;video buffer segment
- delta dw ? ;line length variable
- linelength dw ? ;line length in bytes
- keyboard label dword
- old9h dw 2 dup (?) ;old interrupt 9h vector
-
- quit_text db 'Exit to DOS (Y/N)?',0
- save_text db 'Save as: ',0
- box_text db '1-',179,32,32,'2-',186,32,32,'3-',176,32,32,'4-',177,32,32
- db '5-',178,32,32,'6-',219,32,32,'7-*',0
- fore_text db 'Foreground: 0 1 2 3 4 5 6 7 8 9 '
- db 'A B C D E F',0
- back_text db 'Back',0
- mono_text db '1-Normal 2-Reverse 3-Bold 4-Underline',0
- block_text db '1-Clear 2-Paint',0
- mode_text db '1-Text Only 2-Text and Attributes',0
- help_text db 'F1-Help F2-Attribute F3-Line F4-Mode F5-Block '
- db 'F6-Save F7-Quit',0
-
- key_table db 81,73,65,64,63,62,61,60,59,160,157,155,152,145,116
- db 115,141,83,82,79,71,80,77,75,72
- gr_table db 17,81,145,98,96,144,162,34,160,130,66,129,80
- db 5,69,84,21,68,85,25,38,10,40,138,168,42,136
- db 170,137,70,152,100,6,9,24,36,102,153,65,20
- box_table db 176,177,178,219,42
- mono_table db 7,70h,0Fh,1
-
- jump_table dw offset up ;cursor-up key
- dw offset left ;cursor-left key
- dw offset right ;cursor-right key
- dw offset down ;cursor-down key
- dw offset home ;HOME key
- dw offset endkey ;END key
- dw offset insert ;INS key
- dw offset delete ;DEL key
- dw offset up ;Ctrl-Up
- dw offset left ;Ctrl-Left
- dw offset right ;Ctrl-Right
- dw offset down ;Ctrl-Down
- dw offset BoxUp ;Alt-Up
- dw offset BoxLeft ;Alt-Left
- dw offset BoxRight ;Alt-Right
- dw offset BoxDown ;Alt-Down
- dw offset help ;F1
- dw offset SelectAttr ;F2
- dw offset SelectBox ;F3
- dw offset SelectMode ;F4
- dw offset block ;F5
- dw offset save ;F6
- dw offset quit ;F7
- dw offset PgUp ;PgUp
- dw offset PgDn ;PgDn
-
- ;-----------------------------------------------------------------------------
- ;KBINT handles interrupt 9 and generates new extended keycodes.
- ;-----------------------------------------------------------------------------
- kbint proc near
- sti ;interrupts on
- push ax ;save AX and BX
- push bx
- in al,60h ;read scan code
- cmp al,72 ;cursor up?
- je checkctrl
- cmp al,75 ;cursor left?
- je checkctrl
- cmp al,77 ;cursor right?
- je checkctrl
- cmp al,80 ;cursor down?
- je checkctrl
- oldint: pop bx ;restore AX and BX
- pop ax
- jmp keyboard ;exit to BIOS handler
- ;
- ;Generate extended codes for Ctrl-Up, Down.
- ;
- checkctrl: mov bl,al ;save scan code in BL
- mov ah,2 ;get shift key status
- int 16h
- test al,4 ;Ctrl key pressed?
- jz checkalt ;no, then check Alt key
- cmp bl,75 ;pass left or right key to BIOS
- je oldint
- cmp bl,77
- je oldint
- add bl,45h ;create new extended code
- cmp bl,141
- je process
- mov bl,145
- jmp short process ;process it
- ;
- ;Generate extended codes for Alt-Up, Down, Left, and Right.
- ;
- checkalt: test al,8 ;Alt key pressed?
- jz oldint ;no, then exit to BIOS
- add bl,50h ;create new extended code
- ;
- ;Reset the keyboard and clear the interrupt.
- ;
- process: in al,61h ;read control port value
- mov ah,al ;save it in AH
- or al,80h ;set the high bit
- out 61h,al ;reset keyboard
- mov al,ah ;retrieve original value
- out 61h,al ;enable keyboard
- cli
- mov al,20h ;end the interrupt
- out 20h,al
- sti
- ;
- ;Insert the new keycode into the keyboard buffer.
- ;
- mov ah,bl ;transfer code to AH
- xor al,al ;zero AL
- push dx ;save DX and DS
- push ds
- mov bx,bios_data ;point DS to BIOS data area
- mov ds,bx
- assume ds:bios_data
- cli ;interrupts off
- mov bx,buffer_tail ;get current tail address
- mov dx,bx ;transfer it to DX
- add dx,2 ;advance to next position
- cmp dx,buffer_end ;wrap around if necessary
- jne buffer
- mov dx,buffer_start
- buffer: cmp dx,buffer_head ;is the buffer full?
- je kbexit ;yes, then exit now
- mov [bx],ax ;insert keycode into buffer
- mov buffer_tail,dx ;advance tail
- kbexit: sti ;enable interrupts
- pop ds ;restore registers
- assume ds:nothing
- pop dx
- pop bx
- pop ax
- iret ;and exit
- kbint endp
-
- ;-----------------------------------------------------------------------------
- ;MAIN is the main procedure.
- ;-----------------------------------------------------------------------------
- main proc near
- assume cs:code,ds:code,es:code
- ;
- ;Request 64K of memory for buffer space.
- ;
- mov ah,4Ah ;release memory beyond code seg
- mov bx,4096
- int 21h
- mov ah,48h ;request 4000 paragraphs
- mov bx,4000
- int 21h
- jnc save_seg ;continue if request granted
- mov dx,offset errmsg3 ;abort if request denied
- jmp short error_exit
- save_seg: mov data_segment,ax ;save data segment
- ;
- ;Parse the command line for a filename.
- ;
- cld ;clear DF
- mov si,81h ;point SI to command line
- parse1: lodsb ;find first non-space
- cmp al,32
- je parse1
- cmp al,13 ;end-of-line?
- jne filefound ;no, then it's a filename
- mov byte ptr ds:[81h],0 ;place delimiter for no file
- jmp short exbios ;skip file load
- filefound: dec si ;save starting text address
- mov fileptr,si
- mov bl,ds:[80h] ;zero last byte in string
- xor bh,bh
- mov byte ptr ds:[bx+81h],0
- ;
- ;Open the file designated on the command line for input.
- ;
- mov ax,3D00h ;request read-only access
- mov dx,si ;point DS:DX to filespec
- int 21h
- jnc read_file ;branch if open succeeded
- mov dx,offset errmsg1 ;print 'File not found'
- error_exit: mov ah,9
- int 21h
- mov ax,4C01h ;terminate with error code
- int 21h
- ;
- ;Read character/attribute data from the file.
- ;
- read_file: mov bx,ax ;transfer file handle to BX
- mov ah,3Fh ;read file data
- mov cx,64000 ;request 64,000 bytes
- push ds ;point DS to data segment
- mov ds,data_segment
- assume ds:nothing
- xor dx,dx ;point DX to beginning of segment
- int 21h
- pop ds ;restore DS
- assume ds:code
- jnc check_read ;branch if no error occurred
- mov dx,offset errmsg2 ;abort on read error
- jmp short error_exit
- check_read: or ax,ax ;abort if no bytes read
- jne paginate
- mov dx,offset errmsg2
- jmp short error_exit
- paginate: dec ax ;decrement count by 1
- xor dx,dx ;determine number of pages
- mov bx,4000
- div bx
- mov maxpage,al ;save maximum page number
- close_file: mov ah,3Eh ;close file
- int 21h
- ;
- ;Determine whether or not the BIOS supports extended keyboard functions.
- ;
- exbios: mov ah,5 ;write FFFFh to keyboard buffer
- mov cx,0FFFFh
- int 16h
- mov ah,10h ;then read it back
- int 16h
- cmp ax,0FFFFh ;is AX set correctly?
- je video ;yes, then don't reset INT 9
- ;
- ;Point the interrupt 9 vector to the internal keyboard handler.
- ;
- mov kbcode,0 ;modify KBCODE for old BIOS
- push es
- assume es:nothing
- mov ax,3509h ;get current vector
- int 21h
- mov old9h,bx ;save it
- mov old9h[2],es
- mov ax,2509h ;then reset it
- mov dx,offset kbint
- int 21h
- pop es
- assume es:code
- ;
- ;Determine whether video is color or monochrome.
- ;
- video: push ds ;get address of CRT Controller
- mov ax,bios_data
- mov ds,ax
- assume ds:bios_data
- mov ax,addr_6845
- mov crtc_addr,ax ;save it
- pop ds
- assume ds:code
- test ax,40h ;is bit 6 of CRTC address set?
- jnz more_video ;yes, then it's a color adapter
- inc mode ;no, then it's monochrome
- mov video_segment,0B000h ;modify attributes for monochrome
- mov attribute,7
- mov menu_attr,7
- ;
- ;Determine number of display columns, screen color, and video page number.
- ;
- more_video: mov ah,15 ;get number of columns and page
- int 10h
- mov al,ah
- xor ah,ah
- mov lcolumns,ax ;store number of columns
- mov linelength,ax ;store line length in bytes
- shl linelength,1
- dec al ;store number of columns - 1
- mov columns,al
- mov cl,79 ;determine number of bytes
- sub cl,al ; from end of one line to
- shl cl,1 ; beginning of next
- xor ch,ch
- mov delta,cx
- cmp al,79 ;adjust if more than 80 columns
- jna no_adjust ; are currently displayed
- mov columns,79
- mov lcolumns,80
- mov delta,0
- no_adjust: mov ah,8 ;read current attribute
- int 10h
- mov doscolor,ah ;store it for use upon exit
- or bh,bh ;make sure page zero is active
- je clrscr
- mov ax,0500h ;activate it if it's not
- int 10h
- ;
- ;Clear the screen or write data read from screen file to video memory.
- ;
- clrscr: cmp byte ptr ds:[81h],0 ;was a data file read?
- jne show_file ;yes, then display contents
- mov bh,attribute ;no, then clear the screen
- call ClearScreen
- jmp short getkey ;leave starting screen blank
- show_file: call ShowFile
- ;
- ;Solicit keystrokes and process non-extended keycodes.
- ;
- getkey: call ReadKey ;get a keystroke
- or al,al ;branch on entry of extended code
- je excode
- cmp al,0E0h
- je excode
- cmp al,8 ;BACKSPACE key?
- jne enter
- or dl,dl ;currently at left edge of screen?
- je getkey ;yes, then ignore it
- call backspace ;delete last character
- jmp short getkey ;return for more
- enter: cmp al,13 ;ENTER key?
- jne escape
- mov ah,2 ;advance cursor to next line
- xor bh,bh
- inc dh
- cmp dh,25 ;wrap around if necessary
- jne nowrap
- xor dh,dh
- nowrap: xor dl,dl
- int 10h
- jmp short getkey ;return for more
- escape: cmp al,27 ;ESC key?
- jne charkey
- mov blockxy,0FFFFh ;reset block indicator
- jmp short getkey ;return for more
- charkey: cmp al,32 ;character key?
- jb getkey ;no, then ignore it
- call WriteChar ;yes, then process it
- jmp short getkey ;return for more
- ;
- ;Process an extended keycode.
- ;
- excode: mov al,ah ;transfer keycode to AL
- mov di,offset key_table ;point DI to keycode table
- mov cx,25 ;25 keycodes to check
- repne scasb ;scan table for current keycode
- jne getkey ;return if keycode not found
- mov bx,cx ;move index to BX
- pcall: shl bx,1 ;double it
- call cs:[offset jump_table+bx] ;call handling routine
- mov ah,3 ;get cursor position
- xor bh,bh
- int 10h
- jmp short getkey ;return for more
- main endp
-
- ;-----------------------------------------------------------------------------
- ;ShowFile displays a 4000-byte block indexed by DATA_SEGMENT and BUFFERPTR.
- ;-----------------------------------------------------------------------------
- ShowFile proc near
- mov ax,4000 ;find starting buffer address
- mov bl,bufferptr
- xor bh,bh
- mul bx
- mov si,ax ;transfer it to SI
- push ds ;point DS to data segment
- assume ds:nothing
- mov ds,data_segment
- xor dx,dx ;set DX for home cursor position
- mov cx,25 ;25 display lines
- show1: push cx
- mov cx,lcolumns ;number of display columns
- show2: push cx
- mov ah,2 ;position the cursor
- int 10h
- lodsw ;get one C/A pair
- mov bl,ah ;transfer attribute to BL
- mov ah,9 ;display character and attribute
- mov cx,1
- int 10h
- inc dl ;advance cursor
- pop cx
- loop show2 ;loop until this line is done
- inc dh ;home cursor to start of next line
- xor dl,dl
- add si,delta ;adjust SI for other than 80 cols
- pop cx
- loop show1 ;loop until 25 lines are done
- pop ds ;restore DS
- assume ds:code
- mov ah,2 ;home the cursor
- xor dx,dx
- int 10h
- ret ;and exit
- ShowFile endp
-
- ;-----------------------------------------------------------------------------
- ;ReadKey reads a keypress.
- ;Exit: AX - keycode
- ;-----------------------------------------------------------------------------
- ReadKey proc near
- mov ah,kbcode ;get function code
- inc ah
- int 16h ;check buffer status
- jnz read ;branch if a keycode is ready
- int 28h ;generate interrupt 28h
- jmp short ReadKey ;enter polling loop again
- read: mov ah,kbcode ;read key
- int 16h
- ret ;and exit
- ReadKey endp
-
- ;-----------------------------------------------------------------------------
- ;ClearScreen clears the 25-line viewing area and homes the cursor.
- ;Entry: BH - attribute
- ;-----------------------------------------------------------------------------
- ClearScreen proc near
- mov ax,0600h ;clear screen with function 6
- xor cx,cx
- mov dh,24
- mov dl,columns
- int 10h
- mov ah,2 ;home the cursor
- xor dx,dx
- xor bh,bh
- int 10h
- ret
- ClearScreen endp
-
- ;-----------------------------------------------------------------------------
- ;HELP presents a help line denoting function key assignments.
- ;-----------------------------------------------------------------------------
- help proc near
- mov si,offset help_text ;display help text
- call MenuLine
- help1: call readkey ;wait for a keypress
- call RestoreLine ;erase the help line
- ret
- help endp
-
- ;-----------------------------------------------------------------------------
- ;QUIT exits the application.
- ;-----------------------------------------------------------------------------
- quit proc near
- mov si,offset quit_text ;display menu line
- call MenuLine
- quit1: call ReadKey ;get a keypress
- and al,0DFh ;capitalize response
- cmp al,'Y' ;was the response 'Yes?'
- je quit2 ;yes, then exit
- cmp al,'N' ;was the response 'No?'
- je quit4 ;yes, then return to application
- cmp al,27 ;ESC key?
- je quit4 ;yes, then return to application
- jmp short quit1 ;get another keypress
- quit2: mov bh,doscolor ;clear screen before exit
- call ClearScreen
- mov ah,1 ;restore the cursor
- mov cx,cursor_mode
- int 10h
- cmp kbcode,10h ;skip ahead if extended BIOS
- je quit3
- xor ax,ax ;restore the interrupt 9 vector
- mov es,ax
- cli
- mov ax,old9h
- mov es:[24h],ax
- mov ax,old9h[2]
- mov es:[26h],ax
- sti
- quit3: add sp,4 ;clean up the stack
- mov ah,9
- mov dx,offset copyright
- int 21h
- mov ax,4C00h ;terminate
- int 21h
- quit4: call RestoreLine ;restore menu line
- ret ;return to application
- quit endp
-
- ;-----------------------------------------------------------------------------
- ;SAVE saves the current screen to disk.
- ;-----------------------------------------------------------------------------
- save proc near
- mov si,offset save_text ;display menu line
- call MenuLine
- mov ah,1 ;display cursor
- mov cx,cursor_mode
- int 10h
- getname: mov si,fileptr ;read filespec from keyboard
- mov di,si
- mov cl,70
- mov dx,1809h
- call ReadString
- or cl,cl ;stop if nothing was entered
- jne save_file
- call RestoreLine
- ret
- save_file: mov ah,3Ch ;open the file for writing
- xor cx,cx
- mov dx,fileptr
- int 21h
- jc save_error ;jump on error
- push ax ;save file handle
- call RestoreLine ;restore menu line
- mov ah,3 ;read and save cursor position
- xor bh,bh
- int 10h
- push dx
- call PutVideo ;copy video to data buffer
- mov ah,2 ;reset cursor
- pop dx
- int 10h
- mov ax,4000 ;write data to disk
- mov bl,maxpage
- inc bl
- xor bh,bh
- mul bx
- mov cx,ax
- mov ah,40h
- pop bx
- push ds
- mov ds,data_segment
- assume ds:nothing
- xor dx,dx
- int 21h
- pop ds
- assume ds:code
- mov ah,3Eh ;close the file
- int 21h
- ret
- ;
- ;An error was encountered opening the file. Resolicit the filespec.
- ;
- save_error: mov ax,0E07h ;beep
- int 10h
- mov ah,2 ;reset cursor
- mov dx,1809h
- xor bh,bh
- int 10h
- jmp getname ;solicit filespec again
- save endp
-
- ;-----------------------------------------------------------------------------
- ;PutVideo writes the current video page to the data buffer.
- ;-----------------------------------------------------------------------------
- PutVideo proc near
- push es ;point ES:DI to buffer
- mov es,data_segment
- assume es:nothing
- mov ax,4000
- mov bl,bufferptr
- xor bh,bh
- mul bx
- mov di,ax
- xor dx,dx
- mov cx,25 ;copy contents a line at a time
- put2: push cx
- mov cx,lcolumns
- put3: mov ah,2
- int 10h
- mov ah,8
- int 10h
- stosw
- inc dl
- loop put3
- add di,delta ;adjust for other than 80 columns
- inc dh
- xor dl,dl
- pop cx
- loop put2
- pop es ;restore ES and exit
- assume es:code
- ret
- PutVideo endp
-
- ;-----------------------------------------------------------------------------
- ;BLOCK function allows screen regions to be cleared or painted.
- ;-----------------------------------------------------------------------------
- bwidth db ? ;block width in columns
- firstcol db ? ;starting column number of block
- c_loc dw ? ;cursor position
-
- block proc near
- cmp blockxy,0FFFFh ;first corner?
- jne block1 ;no, then branch
- mov blockxy,dx ;yes, then save cursor position
- ret ;and exit
- block1: mov cx,blockxy ;retrieve opposite corner location
- cmp cx,dx ;are CX and DX the same?
- jne notfull ;no, then branch
- xor cx,cx ;yes, then indicate full screen
- mov dh,24
- mov dl,columns
- jmp short block3
- notfull: cmp cl,dl ;swap if necessary
- jbe block2
- xchg cl,dl
- block2: cmp ch,dh
- jbe block3
- xchg ch,dh
- block3: push cx ;save block parameters
- push dx
- mov si,offset block_text ;display menu line
- call MenuLine
- ;
- ;Block corners are recorded. Get menu option and act accordingly.
- ;
- block4: call ReadKey ;get response
- cmp al,27 ;ESC key?
- jne block5
- mov blockxy,0FFFFh ;reset block definition
- call RestoreLine ;restore menu line
- pop dx ;clean up the stack and exit
- pop cx
- ret
- ;
- ;Clear the indicated region if menu option '1' was selected.
- ;
- block5: cmp al,'1' ;clear region?
- jne block6
- call RestoreLine ;restore last line
- pop dx ;retrieve block corrdinates
- pop cx
- mov ax,0600h ;yes, then clear contents
- mov bh,attribute
- int 10h
- mov blockxy,0FFFFh ;reset block function
- ret
- ;
- ;Paint the indicated region if menu option '2' was selected.
- ;
- block6: cmp al,'2' ;paint region?
- jne block4
- call RestoreLine ;restore menu line
- mov ah,3 ;get cursor position
- xor bh,bh
- int 10h
- mov c_loc,dx ;save it
- pop cx ;retrieve and swap parameters
- pop dx
- mov firstcol,dl ;save starting column number
- sub cl,dl ;determine block width
- inc cl
- mov bwidth,cl
- sub ch,dh ;then block height
- inc ch
- mov cl,ch
- xor ch,ch
- block7: push cx ;scan region and set attributes
- mov cl,bwidth
- xor ch,ch
- block8: push cx
- mov ah,2 ;position cursor
- int 10h
- call SetAttribute ;set current attribute
- inc dl ;advance to next column
- pop cx
- loop block8 ;loop until this line is complete
- inc dh ;advance to next row
- mov dl,firstcol
- pop cx
- loop block7 ;loop until all lines are done
- mov ah,2 ;restore cursor position
- mov dx,c_loc
- int 10h
- mov blockxy,0FFFFh ;reset block function
- ret
- block endp
-
- ;-----------------------------------------------------------------------------
- ;Box routines process presses of Alt-Up, Down, Right, and Left.
- ;-----------------------------------------------------------------------------
- BoxUp proc near
- or dh,dh ;top line?
- je boxup1 ;yes, then ignore keypress
- mov al,7 ;generate default code
- mul graphics
- add al,179
- mov bx,dx ;define next cursor location
- dec bh
- mov boxid,16 ;bias box code
- call DrawChars ;draw box characters
- boxup1: ret
- BoxUp endp
-
- BoxDown proc near
- cmp dh,24 ;bottom line?
- je boxdn1 ;yes, then ignore keypress
- mov al,7 ;generate default code
- mul graphics
- add al,179
- mov bx,dx ;define next cursor location
- inc bh
- mov boxid,1 ;bias box code
- call DrawChars ;draw box characters
- boxdn1: ret
- BoxDown endp
-
- BoxLeft proc near
- or dl,dl ;left edge of screen?
- je boxlf1 ;yes, then ignore keypress
- mov al,9 ;generate default code
- mul graphics
- add al,196
- mov bx,dx ;define next cursor location
- dec bl
- mov boxid,4 ;bias box code
- call DrawChars ;draw box characters
- boxlf1: ret
- BoxLeft endp
-
- BoxRight proc near
- cmp dl,columns ;right edge of screen?
- je boxrt1 ;yes, then ignore keypress
- mov al,9 ;generate default code
- mul graphics
- add al,196
- mov bx,dx ;define next cursor location
- inc bl
- mov boxid,64 ;bias box code
- call DrawChars ;draw box characters
- boxrt1: ret
- BoxRight endp
-
- ;-----------------------------------------------------------------------------
- ;DrawChars is called by the directional box routines to draw box characters.
- ;Entry: AL - default box character
- ; BX - next cursor position
- ;-----------------------------------------------------------------------------
- DrawChars proc near
- mov defchar,al ;store default code
- push bx ;save next cursor location
- cmp graphics,0 ;adjust BOXID if double line
- je drawc1
- shl boxid,1
- drawc1: call DrawBox ;draw character in current cell
- mov ah,2 ;move cursor
- pop dx
- xor bh,bh
- int 10h
- mov boxid,0 ;reset box code
- call DrawBox ;draw next box character
- ret
- DrawChars endp
-
- ;-----------------------------------------------------------------------------
- ;DrawBox draws the appropriate box character at the current cursor position.
- ;-----------------------------------------------------------------------------
- DrawBox proc near
- cmp graphics,1 ;branch if line drawing characters
- jna db1 ; are selected
- mov al,graphics ;form character code
- sub al,2
- mov bx,offset box_table
- xlat box_table
- jmp short db3 ;display character and exit
- db1: call GetEnv ;determine character code
- mov al,boxid ;transfer to AL
- mov cl,4 ;generate desired character code
- rol al,cl
- mov cx,40 ;see if character exists
- mov di,offset gr_table
- repne scasb
- je db2 ;display it if it does
- and al,maskval ;mask mixed characters
- mov cx,40 ;search again
- mov di,offset gr_table
- repne scasb
- je db2
- mov al,defchar ;default to line character
- jmp short db3
- db2: mov al,218 ;print the character
- sub al,cl
- db3: call DisplayChar
- ret
- DrawBox endp
-
- ;-----------------------------------------------------------------------------
- ;SelectMode lets the user specify whether attributes will be inserted
- ;along with typed text.
- ;-----------------------------------------------------------------------------
- SelectMode proc near
- mov si,offset mode_text ;display menu line
- call MenuLine
- sm1: call ReadKey ;get response
- cmp al,27 ;check for ESC key
- je sm2
- cmp al,'1' ;reject invalid entries
- jb sm1
- cmp al,'2'
- ja sm1
- sub al,'1' ;normalize entry
- mov write_mode,al ;save it
- sm2: call Restoreline ;close and exit
- ret
- SelectMode endp
-
- ;-----------------------------------------------------------------------------
- ;SelectBox pops up the box character selection menu.
- ;-----------------------------------------------------------------------------
- SelectBox proc near
- mov si,offset box_text ;display menu line
- call MenuLine
- sb1: call ReadKey ;get response
- cmp al,27 ;ESC key?
- je sb3 ;yes, then exit
- cmp al,13 ;ENTER?
- je sb3 ;yes, then exit
- cmp al,'1' ;reject invalid responses
- jb sb1
- cmp al,'7'
- ja sb1
- sub al,'1' ;normalize entry
- mov graphics,al ;then store it
- or al,al ;set mask value
- jne sb2
- mov maskval,01010101b
- jmp short sb3
- sb2: cmp al,1
- jne sb3
- mov maskval,10101010b
- sb3: call RestoreLine ;restore menu line
- ret
- SelectBox endp
-
- ;-----------------------------------------------------------------------------
- ;SelectAttr pops up the screen attribute selection menu.
- ;-----------------------------------------------------------------------------
- tmpcol db ? ;attribute under cursor
-
- SelectAttr proc near
- mov ah,8 ;get attribute under cursor
- xor bh,bh
- int 10h
- mov tmpcol,ah ;save it
- cmp mode,0 ;color video?
- je sa0 ;yes, then branch
- ;
- ;Display attribute menu for monochrome systems.
- ;
- mov si,offset mono_text ;display menu line
- call MenuLine
- mono1: call ReadKey ;get response
- or al,al ;function key F2?
- jne mono2
- cmp ah,60
- jne mono1
- mov ah,tmpcol ;use attribute under cursor
- mov attribute,ah
- jmp short mono3 ;exit
- mono2: cmp al,27 ;exit if ESC was pressed
- je mono3
- cmp al,'1' ;reject invalid responses
- jb mono1
- cmp al,'4'
- ja mono1
- sub al,'1' ;normalize entry
- mov bx,offset mono_table ;determine new attribute
- xlat mono_table
- mov attribute,al ;save it
- mono3: call RestoreLine ;restore line and exit
- ret
- ;
- ;Display attribute menu for color systems.
- ;
- sa0: mov si,offset fore_text ;display menu line
- call MenuLine
- mov dx,180Eh ;display colors
- xor bx,bx
- sa1: mov ah,2
- int 10h
- mov ax,09DBh
- mov cx,2
- int 10h
- add dl,4
- inc bl
- test bl,10h
- jz sa1
- sa2: call ReadKey ;get foreground color response
- or al,al ;function key F2?
- jne notf1
- cmp ah,60
- jne sa2
- mov ah,tmpcol ;use attribute under cursor
- mov attribute,ah
- jmp short endselect ;and exit
- notf1: cmp al,13 ;ENTER key?
- je sa4
- cmp al,27 ;ESC?
- je endselect
- cmp al,'0' ;reject invalid responses
- jb sa2
- cmp al,'9'
- jna sa3
- and al,0DFh ;normalize entry
- cmp al,'A'
- jb sa2
- cmp al,'F'
- ja sa2
- sub al,7
- sa3: sub al,30h
- and attribute,0F0h ;modify foreground color
- or attribute,al
- sa4: mov si,offset back_text ;display background colors
- mov dx,1800h
- mov bl,menu_attr
- call WriteLine
- mov ah,2
- mov dx,182Ch
- int 10h
- mov ax,0920h
- mov cx,34
- int 10h
- sa5: call ReadKey ;get background color response
- cmp al,13
- je endselect
- cmp al,27
- je endselect
- cmp al,'0'
- jb sa4
- cmp al,'7'
- ja sa4
- sub al,30h
- mov cl,4
- shl al,cl
- and attribute,0Fh ;modify background color
- or attribute,al
- endselect: call RestoreLine ;restore menu line
- ret
- SelectAttr endp
-
- ;-----------------------------------------------------------------------------
- ;WriteChar processes a press of a character key.
- ;-----------------------------------------------------------------------------
- WriteChar proc near
- cmp insert_flag,0 ;insert state on?
- je disp_char ;no, then skip insert sequence
- mov cl,columns ;calculate number of shifts
- sub cl,dl
- xor ch,ch
- jcxz disp_char
- push ax ;save character and position
- push dx
- call VideoAddr ;calculate video address
- mov bx,cx ;determine starting address
- shl bx,1
- add si,bx
- mov di,si
- sub si,2
- push ds ;save DS and ES
- push es
- assume ds:nothing,es:nothing
- mov ds,video_segment
- mov es,video_segment
- std ;set DF temporarily
- mov dx,crtc_addr ;get CRT Controller address
- add dx,6 ;address status register
- vwait: in al,dx ;wait for vertical retrace
- test al,8
- jz vwait
- cmp write_mode,0 ;push text and attributes?
- jne push_all ;yes, then branch
- write_loop: movsb ;shift text only
- dec si
- dec di
- loop write_loop
- jmp short shift_done
- push_all: rep movsw ;shift text and attributes
- shift_done: cld ;restore DF
- pop es ;restore DS and ES
- pop ds
- assume ds:code,es:code
- pop dx ;retrieve character and position
- pop ax
- disp_char: call DisplayChar ;display the character
- mov ah,2 ;advance the cursor
- cmp dl,columns ;prevent overrun
- je nomove
- inc dl
- nomove: int 10h
- ret
- WriteChar endp
-
- ;-----------------------------------------------------------------------------
- ;VideoAddr calculates the page zero video buffer address that corresponds
- ;to the cursor coordinates held in DX.
- ;Entry: DH,DL - cursor row and column | Exit: SI - buffer offset
- ;-----------------------------------------------------------------------------
- VideoAddr proc near
- mov ax,linelength ;row * 160
- mul dh
- shl dl,1 ;add column * 2
- xor dh,dh
- add ax,dx
- mov si,ax ;transfer to SI
- ret
- VideoAddr endp
-
- ;-----------------------------------------------------------------------------
- ;INSERT processes a press of the INS key.
- ;-----------------------------------------------------------------------------
- insert proc near
- xor insert_flag,1 ;toggle flag
- ret
- insert endp
-
- ;-----------------------------------------------------------------------------
- ;UP processes a press of Cursor-Up or Ctrl-Up.
- ;-----------------------------------------------------------------------------
- up proc near
- or dh,dh ;currently on top row?
- je done ;yes, then ignore the keypress
- push ax ;save keycode
- cmp al,100 ;paint cell if Ctrl is pressed
- jb up1
- call SetAttribute
- up1: dec dh ;move cursor up a row
- set_cursor: mov ah,2
- xor bh,bh
- int 10h
- pop ax ;retrieve keycode
- cmp al,100 ;paint cell if Ctrl is pressed
- jb done
- call SetAttribute
- done: ret
- up endp
-
- ;-----------------------------------------------------------------------------
- ;LEFT processes a press of Cursor-Left or Ctrl-Left.
- ;-----------------------------------------------------------------------------
- left proc near
- or dl,dl ;currently at left edge?
- je done ;yes, then ignore the keypress
- push ax ;save keycode
- cmp al,100 ;paint cell if Ctrl is pressed
- jb lf1
- call SetAttribute
- lf1: dec dl ;move cursor left one column
- jmp short set_cursor
- left endp
-
- ;-----------------------------------------------------------------------------
- ;RIGHT processes a press of Cursor-Right or Ctrl-Right.
- ;-----------------------------------------------------------------------------
- right proc near
- cmp dl,columns ;currently at right border?
- je done ;yes, then ignore the keypress
- push ax ;save keycode
- cmp al,100 ;paint cell if Ctrl is pressed
- jb rt1
- call SetAttribute
- rt1: inc dl ;move cursor right one column
- jmp short set_cursor
- right endp
-
- ;-----------------------------------------------------------------------------
- ;DOWN processes a press of Cursor-Down or Ctrl-Down.
- ;-----------------------------------------------------------------------------
- down proc near
- cmp dh,24 ;currently on bottom row?
- je done ;yes, then ignore the keypress
- push ax ;save keycode
- cmp al,100 ;paint cell if Ctrl is pressed
- jb dn1
- call SetAttribute
- dn1: inc dh ;move cursor down a row
- jmp short set_cursor
- down endp
-
- ;-----------------------------------------------------------------------------
- ;HOME processes a press of the HOME key.
- ;-----------------------------------------------------------------------------
- home proc near
- xor dl,dl ;set cursor to start of line
- home1: mov ah,2
- xor bh,bh
- int 10h
- ret
- home endp
-
- ;-----------------------------------------------------------------------------
- ;ENDKEY processes a press of the END key.
- ;-----------------------------------------------------------------------------
- endkey proc near
- mov dl,columns ;set cursor to end of line
- jmp home1
- endkey endp
-
- ;-----------------------------------------------------------------------------
- ;PgUp and PgDn routines flip to the last/next page in the buffer.
- ;-----------------------------------------------------------------------------
- PgUp proc near
- cmp maxpage,0 ;ignore if there's only one page
- je nopress
- call PutVideo ;write current page to buffer
- dec bufferptr ;go back one page
- test bufferptr,80h ;wrap around if necessary
- jz pg1
- mov al,maxpage
- mov bufferptr,al
- pg1: call ShowFile ;display new page
- nopress: ret ;exit
- PgUp endp
-
- PgDn proc near
- cmp maxpage,0 ;ignore if there's only one page
- je nopress
- call PutVideo
- inc bufferptr ;advance page pointer
- mov al,maxpage ;wrap if necessary
- cmp al,bufferptr
- jae pg1
- mov bufferptr,0
- jmp short pg1
- PgDn endp
-
- ;-----------------------------------------------------------------------------
- ;DisplayChar writes the character in AL to the current cursor position.
- ;-----------------------------------------------------------------------------
- DisplayChar proc near
- mov ah,9
- cmp write_mode,0 ;write attribute also?
- jne dc1
- inc ah ;no, then change function number
- dc1: xor bh,bh
- mov bl,attribute
- mov cx,1
- int 10h
- ret
- DisplayChar endp
-
- ;-----------------------------------------------------------------------------
- ;SetAttribute sets the attribute of the character under the cursor.
- ;-----------------------------------------------------------------------------
- SetAttribute proc near
- mov ah,8 ;get character
- xor bh,bh
- int 10h
- mov ah,9 ;write character and attribute
- mov bl,attribute
- mov cx,1
- int 10h
- ret
- SetAttribute endp
-
- ;-----------------------------------------------------------------------------
- ;SaveLine saves the contents of the menu line.
- ;-----------------------------------------------------------------------------
- cursor_mode dw ? ;cursor mode
- cursor_pos dw ? ;cursor position
-
- SaveLine proc near
- mov ah,3 ;get cursor position and shape
- xor bh,bh
- int 10h
- mov cursor_mode,cx ;save cursor parameters
- mov cursor_pos,dx
- mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- mov dx,1800h ;set starting cursor position
- mov di,offset data_buffer ;point DI to save buffer
- mov cx,lcolumns
- sr1: mov ah,2 ;position the cursor
- int 10h
- mov ah,8 ;read character and attribute
- int 10h
- stosw ;store them
- inc dl ;advance cursor to next column
- loop sr1 ;loop until line is done
- ret
- SaveLine endp
-
- ;-----------------------------------------------------------------------------
- ;RestoreLine restores the contents of the previously saved menu line.
- ;-----------------------------------------------------------------------------
- RestoreLine proc near
- mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- xor bh,bh
- mov si,offset data_buffer ;point SI to saved char/attr's
- mov cx,lcolumns
- mov dx,1800h ;initialize cursor position
- rr1: push cx
- mov ah,2 ;position the cursor
- int 10h
- lodsw ;get character and attribute
- mov bl,ah ;transfer attribute to BL
- mov ah,9 ;write character and attribute
- mov cx,1
- int 10h
- inc dl ;advance cursor to next column
- pop cx
- loop rr1 ;loop until line is done
- mov ah,2 ;restore cursor position and shape
- mov dx,cursor_pos
- int 10h
- mov ah,1
- mov cx,cursor_mode
- int 10h
- ret
- RestoreLine endp
-
- ;-----------------------------------------------------------------------------
- ;GetEnv returns a value reflecting what lies on all four sides of the cursor.
- ;Entry: DH,DL - cursor position | Exit: BOXID - neighbor code
- ;-----------------------------------------------------------------------------
- c_pos label word
- c_col db ? ;cursor column
- c_row db ? ;cursor row
-
- GetEnv proc near
- mov c_pos,dx ;save cursor position
- call VideoAddr ;calculate video address
- mov dx,crtc_addr
- add dx,6
- push ds ;save DS
- mov ds,video_segment ;point DS to video buffer
- assume ds:nothing
- ;
- ;Determine if what lies on the left affects the current cell.
- ;
- sub si,2 ;address cell on left
- cmp c_col,0 ;at left edge of screen?
- je check2 ;yes, then skip test
- test boxid,12 ;branch if BOXID is biased
- jnz check2
- mov ah,4
- call MakeCode ;generate BOXID code
- ;
- ;Then do the same for the right side.
- ;
- check2: add si,4
- mov al,columns
- cmp c_col,al
- je check4
- test boxid,192
- jnz check4
- mov ah,64
- call MakeCode
- ;
- ;Check the character above the current cell.
- ;
- check4: sub si,linelength
- sub si,2
- cmp c_row,0
- je check6
- test boxid,48
- jnz check6
- mov ah,16
- call MakeCode
- ;
- ;Finish up by checking the character below.
- ;
- check6: add si,linelength
- add si,linelength
- cmp c_row,24
- je check8
- test boxid,3
- jnz check8
- mov ah,1
- call MakeCode
- check8: pop ds ;restore DS
- assume ds:code
- mov dx,c_pos ;restore DX
- ret ;and exit
- GetEnv endp
-
- ;-----------------------------------------------------------------------------
- ;MakeCode modifies BOXID to reflect the character addressed by DS:SI.
- ;Entry: DS:SI - character
- ; AH - test value
- ; DX - video status register
- ;-----------------------------------------------------------------------------
- MakeCode proc near
- assume ds:nothing
- call GetChar ;retrieve character
- cmp al,179 ;exit if not a graphics character
- jb make_exit
- cmp al,218
- ja make_exit
- sub al,179 ;check for single extension
- mov bx,offset gr_table
- xlat gr_table
- test al,ah
- jz make1
- or boxid,ah
- jmp short make_exit
- make1: shl ah,1 ;check for double extension
- test al,ah
- jz make_exit
- or boxid,ah
- make_exit: ret
- MakeCode endp
-
- ;-----------------------------------------------------------------------------
- ;GetChar returns the character addressed by DS:SI in AL.
- ;Entry: DS:SI - character cell | Exit: AL - character code
- ; DX - video status register |
- ;-----------------------------------------------------------------------------
- GetChar proc near
- assume ds:nothing
- in al,dx ;wait for horizontal scan
- test al,1
- jnz GetChar
- cli ;interrupts off
- wait1: in al,dx ;wait for next retrace
- test al,1
- jz wait1
- mov al,[si] ;get the character
- sti ;interrupts on
- ret
- GetChar endp
-
- assume ds:code
-
- ;-----------------------------------------------------------------------------
- ;MenuLine opens a menu line at the bottom of the screen.
- ;Entry: DS:SI - text of menu line
- ;-----------------------------------------------------------------------------
- MenuLine proc near
- push si ;save string address
- call SaveLine ;save current line contents
- mov ah,2 ;position cursor on menu line
- xor bh,bh
- mov dx,1800h
- int 10h
- mov ax,0920h ;clear menu line
- mov bl,menu_attr
- mov cx,lcolumns
- int 10h
- pop si ;retrieve string address
- call WriteLine ;display text
- ret
- MenuLine endp
-
- ;-----------------------------------------------------------------------------
- ;WriteLine displays a line of ASCIIZ text.
- ;Entry: DS:SI - text string
- ; DH,DL - cursor row and column
- ;-----------------------------------------------------------------------------
- WriteLine proc near
- mov ah,2 ;position the cursor
- xor bh,bh
- int 10h
- write1: lodsb ;get a character
- or al,al ;exit if it's zero
- je write2
- mov ah,10 ;write it
- mov cx,1
- int 10h
- mov ah,2
- inc dl
- int 10h
- jmp write1 ;loop back for more
- write2: ret
- WriteLine endp
-
- ;-----------------------------------------------------------------------------
- ;ReadString reads a string of text from the keyboard.
- ;Entry: CL - maximum length
- ; DH,DL - cursor position
- ; DS:SI - default string
- ; ES:DI - input buffer
- ;-----------------------------------------------------------------------------
- maxlen db ? ;maximum accepted length
-
- ReadString proc near
- mov maxlen,cl ;store max length
- xor cl,cl ;initialize counter
- xor bh,bh
- rs1: lodsb ;input default string
- or al,al ;end of string?
- je rs2 ;yes, then exit loop
- inc di ;advance buffer pointer
- inc cl ;increment count
- mov ah,14 ;print the character
- int 10h
- jmp short rs1 ;loop until zero byte is reached
- rs2: call ReadKey ;read the keyboard
- cmp al,8 ;BACKSPACE key?
- jne rs3
- or cl,cl ;at beginning of line?
- je rs2 ;yes, then ignore it
- mov ah,14 ;move cursor back one space
- int 10h
- push cx ;delete the last character
- mov ax,0A20h
- mov cx,1
- int 10h
- pop cx
- dec cl ;decrement count and pointer
- dec di
- jmp short rs2 ;return for more
- rs3: cmp al,13 ;ENTER key?
- jne rs4 ;no, then branch
- xor al,al ;mark end of string
- stosb
- ret ;done
- rs4: cmp al,27 ;ESC key?
- jne rs5 ;no, then branch
- xor cl,cl ;zero count
- mov al,cl ;place delimiter
- stosb
- ret
- rs5: cmp al,32 ;ASCII code less than 32?
- jb rs2 ;yes, then ignore it
- cmp cl,maxlen ;room for more?
- je rs2 ;no, then ignore keypress
- stosb ;buffer the character
- inc cl ;increment count
- mov ah,14 ;print the character
- int 10h
- jmp short rs2 ;return for more
- ReadString endp
-
- ;-----------------------------------------------------------------------------
- ;BACKSPACE backspaces over the last character.
- ;Entry: DH,DL - cursor row and column
- ;-----------------------------------------------------------------------------
- backspace proc near
- mov ah,2 ;move cursor back one column
- dec dl
- xor bh,bh
- int 10h
- cmp insert_flag,0 ;is insert mode active?
- je bs_exit ;no, then we're done
- push dx ;save cursor position
- call delete ;draw in everything to the right
- pop dx ;retrieve position
- bs_exit: ret
- backspace endp
-
- ;-----------------------------------------------------------------------------
- ;DELETE shifts everything right of the cursor one cell left.
- ;Entry: DH,DL - cursor row and column
- ;-----------------------------------------------------------------------------
- delete proc near
- mov cl,columns ;calculate number of shifts
- sub cl,dl
- xor ch,ch
- jcxz nodelete ;branch if there are none
- call VideoAddr ;calculate video address
- mov di,si
- add si,2
- push ds ;save DS and ES
- push es
- assume ds:nothing,es:nothing
- mov ds,video_segment
- mov es,video_segment
- mov dx,crtc_addr ;get CRT Controller address
- add dx,6 ;address status register
- rwait: in al,dx ;wait for vertical retrace
- test al,8
- jz rwait
- cmp write_mode,0 ;delete text and attribute?
- jne delete_all ;yes, then branch
- del_loop: movsb ;delete text only
- inc si
- inc di
- loop del_loop
- jmp short finish
- delete_all: rep movsw ;shift characters and attributes
- finish: mov byte ptr es:[di],32 ;blank final cell
- pop es ;restore DS and ES
- pop ds
- assume ds:code,es:code
- ret
- nodelete: mov ax,0A20h ;blank character under cursor
- xor bh,bh
- mov cx,1
- int 10h
- ret
- delete endp
-
- data_buffer label byte ;buffer for menu line
-
- code ends
- end begin
-